#ifndef MODBUS_H
#define MODBUS_H

#include <QByteArray>
#include <QVector>

//MOdbus通讯功能码
typedef enum _FUNCTION_CODE{
    _CODE_00=0x00,
    _CODE_01=0x01,
    _CODE_02=0x02,
    _CODE_03=0x03,
    _CODE_04=0x04,
    _CODE_05=0x05,
    _CODE_06=0x06,
    _CODE_0F=0x0F,
    _CODE_10=0x10,
}_FUNCTION_CODE;
//从站返回响应
typedef struct _MODBUS_READ_RESPOND{
    _FUNCTION_CODE _FunCode;//功能吗
    unsigned char _DevAddr;//设备地址
    unsigned char _DataLen;//数据长度
    unsigned int _TCPDataLen;//TCP
    _MODBUS_READ_RESPOND(){
        _FunCode=_FUNCTION_CODE::_CODE_00;
        _DevAddr=0x00;
        _DataLen=0x00;
        _TCPDataLen=0x00;
    }
}_MODBUS_READ_RESPOND;

//modbus从站数据结构
typedef struct _MODBUS_SLAVE{
    _FUNCTION_CODE _FunCode;//功能吗
    unsigned char _DevAddr;//设备地址
    unsigned char _BegAddr_U;//起始地址高字节
    unsigned char _BegAddr_L;//起始地址低字节
    unsigned char _EndAddr_U;//结束地址高字节
    unsigned char _EndAddr_L;//结束地址高字节
    unsigned int _RegCount;//寄存器个数
    bool _IsValid;
    _MODBUS_SLAVE(){
         _FunCode=_FUNCTION_CODE::_CODE_00;
        _DevAddr=0xFF;
        _BegAddr_U=0xFF;
        _BegAddr_L=0xFF;
        _EndAddr_U=0xFF;
        _EndAddr_L=0xFF;
        _RegCount=0x00;
        _IsValid=false;
    }
}_MODBUS_SLAVE;

//modbus协议类型
typedef enum _MODBUS_TYPE{
    _MODBUSRTU=0,
    _MODBUSTCP
}_MODBUS_TYPE;

//从站报文生成封装
class ModbusSlave
{
public:
    ModbusSlave(_MODBUS_TYPE Type=_MODBUS_TYPE::_MODBUSRTU,const QByteArray &data=QByteArray());

    QByteArray RespondFuntionError();//功能码错误响应
    QByteArray RespondRegOverflow();//寄存器溢出响应
    QByteArray RespondWriteData();//写数据响应
    QByteArray RespondReadData(const QByteArray &Respond);//读数据响应

    _MODBUS_SLAVE MbByteToMbSlave(const QByteArray &data);//modbus转Modbus从站结构体
    _MODBUS_SLAVE MbTcpByteToMbSlave(const QByteArray &data);//modbusTCP转Modbus从站结构体
    _MODBUS_SLAVE MbRtuByteToMbSlave(const QByteArray &data);//modbusRTU转Modbus从站结构体
    _MODBUS_SLAVE getMbSlave();//获取从站的结构体
    QByteArray getDataByte();//获取从站被写时的数据字节段

public:
    QByteArray m_DataByte;//获取从站被写时的数据字节段，只读时无效
protected:
    _MODBUS_TYPE m_MbType;//modbus协议类型，是RTU还是TCP
    _MODBUS_SLAVE m_MbSlave;//modbus从站信息结构体，包括地址，功能码起始寄存器，
    QByteArray m_SrcByte;//接收的原始字节数组

};
//------------------------Slave-------------------
//寄存器类型
typedef enum _REGISTER_TYPE{
    _BOOL=0x00,
    _UINT16,
    _UINT32,
    _INT16,
    _INT32,
    _FLOAT32,
}_REGISTER_TYPE;
//寄存器设置
typedef struct _MODBUS_DATA{
    _REGISTER_TYPE type;
    bool m_bool;
    unsigned short int m_uint16;
    unsigned int m_uint32;
    short int m_int16;
    int m_int32;
    float m_float;
    unsigned char _Regisetr_U;//寄存器地址高字节
    unsigned char _Regisetr_L;//寄存器地址低字节
    _MODBUS_DATA(){
        type=_REGISTER_TYPE::_BOOL;
        m_bool=false;
        m_uint16=0;
        m_uint32=0;
        m_int16=0;
        m_int32=0;
        m_float=0;
        _Regisetr_U=0;
        _Regisetr_L=0;
    }
}_MODBUS_DATA;
//主站通信功能封装
class ModbusMaster
{
public:
    /** 主站初始化的时候必须确定协议类型和功能码
     * @brief ModbusMaster modbus主站数据类
     * @param Type modbus协议类型
     * @param code modbus功能码
     */
    ModbusMaster(_MODBUS_TYPE Type=_MODBUS_TYPE::_MODBUSRTU,_FUNCTION_CODE code=_FUNCTION_CODE::_CODE_03);
    /**
     * @brief MbDataToByte 将需要读取的寄存器数据结构体转化为modbus报文
     * @return 返回主站请求的modbus报文
     */
    QByteArray SendDataToByte();
    /**
     * @brief RespondByteToModbusData 将返回的modbus报文转化为转化为modbus结构体数据
     * @param data modbus结构体，事先确定好了寄存器地址，数据类型这些
     * @param Byte 从站返回的modbus报文
     * @return 返回处理结果，-1校验错误，-2地址错误，-3功能码错误，-4数据长度错误，0处理正常
     */
    int RespondByteRead(QByteArray &RespondByte);
    /**
     * @brief RespondByteToValidData 响应的数据获取有效部分，比如TCP把TCP头去掉
     * @RetByte 响应报文处理成有效部分数据
     * @return 返回处理结果，-1校验错误，-2地址错误，-3功能码错误，-4数据长度错误，0处理正常
     */
    int RespondByteIsValid(QByteArray &RetByte,_FUNCTION_CODE FuntionCode);
    /**
     * @brief WriteDataToByte_05 WriteDataToByte_05 写寄存器
     * @param index 写寄存器索引,写内部添加好的数组的寄存器
     * @param ret 返回处理结果 -1数据类型错误，-2数组溢出响应，-3设备不具备05功能码,0正常
     * @return
     */
    QByteArray WriteDataToByte_05(const int index,int &ret);
    QByteArray WriteDataToByte_05(const _MODBUS_DATA &data,int &ret);
    /**
     * @brief RespondByteWrite_05 判断响应数据是否正确
     * @param Byte 返回报文
     * @param SendByte 发送的报文
     * @return 返回处理结果，-1校验错误，-2地址错误，-3功能码错误，-4数据长度错误,-5响应寄存器错误，0处理正常
     */
    int RespondByteWrite_05(QByteArray &RespondByte,const QByteArray &SendByte);
    /**
     * @brief WriteDataToByte_0F 写多个开关量寄存器，
     * @param ret 返回处理结果 -3设备不具备0F功能码,0正常
     * @return
     */
    QByteArray WriteDataToByte_0F(int &ret);
    /**
     * @brief RespondByteWrite_0F 判断响应数据是否正确
     * @param Byte 返回报文
     * @param SendByte 发送的报文
     * @return 返回处理结果，-1校验错误，-2地址错误，-3功能码错误，-4数据长度错误，0处理正常
     */
    int RespondByteWrite_0F(QByteArray &RespondByte,const QByteArray &SendByte);

    QByteArray WriteDataToByte_06(const int index,int &ret);
    QByteArray WriteDataToByte_06(const _MODBUS_DATA &data,int &ret);
    /**
     * @brief WriteDataToByte_06 判断响应数据是否正确
     * @param Byte 返回报文
     * @param SendByte 发送的报文
     * @return 返回处理结果，-1校验错误，-2地址错误，-3功能码错误，-4数据长度错误,-5响应寄存器错误，0处理正常
     */
    int RespondByteWrite_06(QByteArray &RespondByte,const QByteArray &SendByte);

    QByteArray WriteDataToByte_10(const int index,int &ret);
    QByteArray WriteDataToByte_10(const _MODBUS_DATA &data,int &ret);
    /**
     * @brief WriteDataToByte_06 判断响应数据是否正确
     * @param Byte 返回报文
     * @param SendByte 发送的报文
     * @return 返回处理结果，-1校验错误，-2地址错误，-3功能码错误，-4数据长度错误,-5响应寄存器错误，0处理正常
     */
    int RespondByteWrite_10(QByteArray &RespondByte,const QByteArray &SendByte);
    void setModbusAddr(const int addrValue);
    /**
     * @brief getModbusAddr 获取设备地址
     * @return 地址
     */
    int getModbusAddr();
    /**
     * @brief appendData 添加需要读取的数据结构体，会自动计算好需要读取的起始基础寄存器，读取个数
     * @param data 数据结构体
     */
    void appendData(const _MODBUS_DATA &data);
    void appendData(const QVector<_MODBUS_DATA> &data);
    /**
     * @brief getDataVector 获取数据数组
     * @return 返回数据数组存放指针
     */
    QVector<_MODBUS_DATA> &data();
    QVector<_MODBUS_DATA> getDataVector();
    /**
     * @brief clenData 清空数据
     */
    void clenData();
    /**
     * @brief setFuntionCode 设置功能码
     * @param code 功能码
     */
    void setFuntionCode(_FUNCTION_CODE code){ m_MbCode=code; };
    /**
     * @brief setProtocolType 设置协议类型
     * @param Type 协议类型
     */
    void setProtocolType(_MODBUS_TYPE Type){ m_MbType=Type; };
    /**
     * @brief setParseInt** 设置数据解析顺序
     */
    void setParseInt16(int a=0,int b=1);
    void setParseInt32(int a=0,int b=1,int c=2,int d=3);
    void setParseFloat(int a=0,int b=1,int c=2,int d=3);
protected:
    _MODBUS_TYPE m_MbType;
    unsigned int m_Addr;
    _FUNCTION_CODE m_MbCode;

    QVector<_MODBUS_DATA> m_Data;

    int m_begRegigter;
    int m_endRegigter;
    int m_registerCoutn;
    //设置数据解析顺序
    int m_PInt16[2];//16位int型解析顺序
    int m_PInt32[4];//32位int解析顺序
    int m_PFloat[4];//32位浮点型解析顺序
};

#endif // MODBUS_H
